/*
 * Copyright (c) 2020 Tencent Cloud. All rights reserved.

 * Licensed under the MIT License (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://opensource.org/licenses/MIT

 * Unless required by applicable law or agreed to in writing, software distributed under the License is
 * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <string.h>
#include <time.h>
#include <unistd.h>

#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "nvs_flash.h"
#include "esp_wifi.h"
#include "esp_smartconfig.h"
#include "esp_event_loop.h"
#include "esp_log.h"
#include "lwip/apps/sntp.h"

#include "qcloud_iot_demo.h"
#include "qcloud_wifi_config.h"
#include "board_ops.h"
#include "driver/pwm.h"
#include "driver/uart.h"
#include "string.h"
#include "qcloud_iot_export.h"
#include "driver/hw_timer.h"

#define aging_test_c 10 //老化时间，分钟
#define aging_test_w 10
#define aging_test_rgb 10

#define EX_UART_NUM UART_NUM_0
#define BUF_SIZE (1024)
#define RD_BUF_SIZE (BUF_SIZE)
QueueHandle_t uart0_queue;
uart_config_t uart_config = {
    .baud_rate = 115200,
    .data_bits = UART_DATA_8_BITS,
    .parity = UART_PARITY_DISABLE,
    .stop_bits = UART_STOP_BITS_1,
    .flow_ctrl = UART_HW_FLOWCTRL_DISABLE
};
extern char sg_product_id[MAX_SIZE_OF_PRODUCT_ID + 1];
extern char sg_device_name[MAX_SIZE_OF_DEVICE_NAME + 1];
extern char sg_region[MAX_SIZE_OF_REGION + 1] ;
extern char sg_product_secret[MAX_SIZE_OF_PRODUCT_SECRET + 1];
extern char sg_device_secret[MAX_SIZE_OF_DEVICE_SECRET + 1];

void my_pwm_init(void);
void send_light_data(uint8_t COLOR_R,uint8_t COLOR_G,uint8_t COLOR_B,uint8_t COLOR_C,uint8_t COLOR_W);
void get_light_data(void);
void light_change_task(void* parm);
void light_change_timer(void *arg);
void save_data_timer_cb(void);
void device_init(void);
int ABS(int value);
unsigned int get_max_value(unsigned int a, unsigned int b, unsigned int c, unsigned int d, unsigned int e);
void default_value(void);
void set_flash(void);
void get_flash(void);
void light_init(void);
void router_wifi_save_info(uint8_t *ssid, uint8_t *password);
void router_wifi_clean_info(void);
bool router_wifi_read();
uint8_t get_reset_cnt();
void set_reset_cnt(uint8_t cnt);
void reset_cnt_timer_cb(void);
void twinkle_timer_cb(void);
void factory_test(void);
void test_timer_cb(void);
void set_test_cnt(uint32_t cnt);
uint32_t get_test_cnt();
void uart_event_task(void* parm);
void set_product_Info();
void get_product_Info();

bool scale_flag;
QueueHandle_t Light_Queue;
DP_DEF dp_data;
os_timer_t save_data_timer;
os_timer_t reset_cnt_timer;
os_timer_t twinkle_timer;
os_timer_t test_timer;
wifi_config_t wifi_config;
LIGHT_DATA_DEF light_data;
bool wifi_connection_flag;
void *mutex_handle;

#define PWM_PERIOD (1000)
#define PWM_MAX 1024
uint32_t pwm_val = 0;
#define CHANNLE_PWM_TOTAL 5 
#define CHANNLE_PWM_R 0
#define CHANNLE_PWM_G 1
#define CHANNLE_PWM_B 2
#define CHANNLE_PWM_C 3
#define CHANNLE_PWM_W 4
#define PWM_R_OUT_IO_NUM 4
#define PWM_G_OUT_IO_NUM 12
#define PWM_B_OUT_IO_NUM 14
#define PWM_C_OUT_IO_NUM 5
#define PWM_W_OUT_IO_NUM 13
const uint32_t pinNum[CHANNLE_PWM_TOTAL] = {PWM_R_OUT_IO_NUM, PWM_G_OUT_IO_NUM, PWM_B_OUT_IO_NUM,PWM_C_OUT_IO_NUM, PWM_W_OUT_IO_NUM};
// don't alter it !!! dutys table, (duty/PERIOD)*depth , init
uint32_t setDuties[CHANNLE_PWM_TOTAL] = {0,0,0,0,0};
int16_t phase[CHANNLE_PWM_TOTAL] = { 0,0,0,0,0};

static const int CONNECTED_BIT = BIT0;
static EventGroupHandle_t wifi_event_group;
/* normal WiFi STA mode init and connection ops */
//#ifndef CONFIG_WIFI_CONFIG_ENABLED

/* WiFi router SSID  */
#define TEST_WIFI_SSID                 CONFIG_DEMO_WIFI_SSID
/* WiFi router password */
#define TEST_WIFI_PASSWORD             CONFIG_DEMO_WIFI_PASSWORD


bool wait_for_wifi_ready(int event_bits, uint32_t wait_cnt, uint32_t BlinkTime)
{
    EventBits_t uxBits;
    uint32_t cnt = 0;
    uint8_t blueValue = 0;

    // while (cnt++ < wait_cnt)
    while(1)
	{
        uxBits = xEventGroupWaitBits(wifi_event_group, event_bits, true, false, BlinkTime / portTICK_RATE_MS);

        if (uxBits & CONNECTED_BIT) 
		{
            Log_d("WiFi Connected to AP");
            return true;
        }

        blueValue = (~~blueValue) & 0x01;
    }

    xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);

    return false;
}


static void wifi_connection(void)
{
    Log_i("Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);

    ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));

    esp_wifi_connect();
}

static esp_err_t _esp_event_handler(void* ctx, system_event_t* event)
{
    Log_i("event = %d", event->event_id);

    switch (event->event_id) 
	{
        case SYSTEM_EVENT_STA_START:
            Log_i("SYSTEM_EVENT_STA_START");
            wifi_connection();
            wifi_connection_flag=1;
            break;

        case SYSTEM_EVENT_STA_GOT_IP:
            Log_i("Got IPv4[%s]", ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip));
            xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
            wifi_connection_flag=1;
            break;

        case SYSTEM_EVENT_STA_DISCONNECTED:
            Log_i("SYSTEM_EVENT_STA_DISCONNECTED");
            xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
            esp_wifi_connect();
            wifi_connection_flag=0;
            break;

        default:
            break;
    }

    return ESP_OK;
}

static void esp_wifi_initialise(void)
{
    tcpip_adapter_init();

    wifi_event_group = xEventGroupCreate();
    ESP_ERROR_CHECK(esp_event_loop_init(_esp_event_handler, NULL));
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));
    ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_FLASH));

    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
    ESP_ERROR_CHECK(esp_wifi_start());
}

//#endif //#ifnef CONFIG_DEMO_WIFI_BOARDING

void setup_sntp(void )
{
    sntp_setoperatingmode(SNTP_OPMODE_POLL);

    // to set more sntp server, plz modify macro SNTP_MAX_SERVERS in sntp_opts.h file
    // set sntp server after got ip address, you'd better adjust the sntp server to your area
    sntp_setservername(0, "time1.cloud.tencent.com");
    sntp_setservername(1, "cn.pool.ntp.org");
    sntp_setservername(2, "time-a.nist.gov");
    sntp_setservername(3, "cn.ntp.org.cn");

    sntp_init();

    // wait for time to be set
    time_t now = 0;
    struct tm timeinfo = { 0 };
    int retry = 0;
    const int retry_count = 10;

    while (timeinfo.tm_year < (2019 - 1900) && ++retry < retry_count) 
	{
        Log_d("Waiting for system time to be set... (%d/%d)", retry, retry_count);
        sleep(1);
        time(&now);
        localtime_r(&now, &timeinfo);
    }

    // Set timezone to China Standard Time
    setenv("TZ", "CST-8", 1);
    tzset();
}

void qcloud_demo_task(void* parm)
{
    bool wifi_connected = false;
    Log_i("qcloud_demo_task start");


    if(router_wifi_read()==0)
    {
        factory_test();
        int ret = start_smartconfig();
        if (ret) 
        {
            Log_e("start wifi config failed: %d", ret);
        } 
        else 
        {
            os_timer_arm(&twinkle_timer, 250, 1);
            /* max waiting: 150 * 2000ms */
            int wait_cnt = 150;
            do 
            {
                Log_d("waiting for wifi config result...");
                HAL_SleepMs(2000);
                wifi_connected = is_wifi_config_successful();
            } 
            while (!wifi_connected && wait_cnt--);
            os_timer_disarm(&twinkle_timer);
        }
    }
    else
    {
        esp_wifi_initialise();
        wifi_connected = wait_for_wifi_ready(CONNECTED_BIT, 20, 1000);
    }

    if (wifi_connected) 
    {
        setup_sntp();
        Log_i("WiFi is ready, to do Qcloud IoT demo\n");
        Log_d("timestamp now:%d", HAL_Timer_current_sec());

        qcloud_iot_explorer_demo(CONFIG_DEMO_EXAMPLE_SELECT);
    } 
    else 
    {
        Log_e("WiFi is not ready, please check configuration!!!");
        send_light_data(0,0,0,255,0);
    }

    Log_w("\n\nqcloud_demo_task quit!!!!!!!!!!!!!!\n\n");
	
    esp_restart();
 	vTaskDelete(NULL);
}

/*****************************************************************/
void light_change_timer(void *arg)
{
    uint8_t light_change1; 
    light_change1=1;
    xQueueSend(Light_Queue,&light_change1,portMAX_DELAY);
}

void light_change_task(void* parm)
{
    uint8_t light_change;

	signed int delata_red = 0;
	signed int delata_green = 0;
    signed int delata_blue = 0;
    signed int delata_white = 0;
	signed int delata_warm = 0;
    unsigned char MAX_VALUE;
	static float r_scale;
	static float g_scale;
	static float b_scale;
	static float w_scale;
	static float ww_scale;
	unsigned int RED_GRA_STEP = 1;
	unsigned int GREEN_GRA_STEP = 1;
	unsigned int BLUE_GRA_STEP = 1;
	unsigned int WHITE_GRA_STEP = 1;
	unsigned int WARM_GRA_STEP = 1;

    while(1)
    {
        if(xQueueReceive(Light_Queue,(void *)&light_change,portMAX_DELAY))
        {
          HAL_MutexLock(mutex_handle);
		  if(light_data.WHITE_VAL != light_data.LAST_WHITE_VAL || light_data.WARM_VAL != light_data.LAST_WARM_VAL || light_data.RED_VAL != light_data.LAST_RED_VAL ||light_data.GREEN_VAL != light_data.LAST_GREEN_VAL || light_data.BLUE_VAL != light_data.LAST_BLUE_VAL)
	      {
			delata_red = light_data.RED_VAL - light_data.LAST_RED_VAL;
			delata_green = light_data.GREEN_VAL - light_data.LAST_GREEN_VAL;
			delata_blue = light_data.BLUE_VAL - light_data.LAST_BLUE_VAL;
			delata_white = light_data.WHITE_VAL - light_data.LAST_WHITE_VAL;
			delata_warm = light_data.WARM_VAL - light_data.LAST_WARM_VAL;
			MAX_VALUE = get_max_value(ABS(delata_red), ABS(delata_green), ABS(delata_blue), ABS(delata_white), ABS(delata_warm));

			if(scale_flag == 0){
				r_scale = ABS(delata_red)/1.0/MAX_VALUE;
				g_scale = ABS(delata_green)/1.0/MAX_VALUE;
				b_scale = ABS(delata_blue)/1.0/MAX_VALUE;
				w_scale = ABS(delata_white)/1.0/MAX_VALUE;
				ww_scale = ABS(delata_warm)/1.0/MAX_VALUE;
				scale_flag = 1;
			}
			if(MAX_VALUE == ABS(delata_red)){
				RED_GRA_STEP = 1;
			}else{
				RED_GRA_STEP =  ABS(delata_red) - MAX_VALUE*r_scale;
			}
			if(MAX_VALUE == ABS(delata_green)){
				GREEN_GRA_STEP = 1;
			}else{
				GREEN_GRA_STEP =  ABS(delata_green) - MAX_VALUE*g_scale;
			}
			if(MAX_VALUE == ABS(delata_blue)){
				BLUE_GRA_STEP = 1;
			}else{
				BLUE_GRA_STEP =  ABS(delata_blue) - MAX_VALUE*b_scale;
			}
			if(MAX_VALUE == ABS(delata_white)){
				WHITE_GRA_STEP = 1;
			}else{
				WHITE_GRA_STEP =  ABS(delata_white) - MAX_VALUE*w_scale;
			}
			if(MAX_VALUE == ABS(delata_warm)){
				WARM_GRA_STEP = 1;
			}else{
				WARM_GRA_STEP =  ABS(delata_warm) - MAX_VALUE*ww_scale;
			}

			if(delata_red != 0){
			    if(ABS(delata_red) < RED_GRA_STEP)
			    {
					 light_data.LAST_RED_VAL += delata_red;
				}else{
					if(delata_red < 0)
						light_data.LAST_RED_VAL -= RED_GRA_STEP;
					else
						light_data.LAST_RED_VAL += RED_GRA_STEP;
				}
			}
			if(delata_green != 0){
			    if(ABS(delata_green) < GREEN_GRA_STEP)
			    {
					 light_data.LAST_GREEN_VAL += delata_green;
				}else{
					if(delata_green < 0)
						light_data.LAST_GREEN_VAL -= GREEN_GRA_STEP;
					else
						light_data.LAST_GREEN_VAL += GREEN_GRA_STEP;
				}
			}
			if(delata_blue != 0){
			    if(ABS(delata_blue) < BLUE_GRA_STEP)
			    {
					 light_data.LAST_BLUE_VAL += delata_blue;
				}else{
					if(delata_blue < 0)
						light_data.LAST_BLUE_VAL -= BLUE_GRA_STEP;
					else
						light_data.LAST_BLUE_VAL += BLUE_GRA_STEP;
				}
			}
			if(delata_white != 0){
			    if(ABS(delata_white) < WHITE_GRA_STEP)
			    {
					 light_data.LAST_WHITE_VAL += delata_white;
				}else{
					if(delata_white < 0)
						light_data.LAST_WHITE_VAL -= WHITE_GRA_STEP;
					else
						light_data.LAST_WHITE_VAL += WHITE_GRA_STEP;
				}
			}
			if(delata_warm != 0){
			    if(ABS(delata_warm) < WARM_GRA_STEP)
			    {
					 light_data.LAST_WARM_VAL += delata_warm;
				}else{
					if(delata_warm < 0)
						light_data.LAST_WARM_VAL -= WARM_GRA_STEP;
					else
						light_data.LAST_WARM_VAL += WARM_GRA_STEP;
				}
			}
             send_light_data(light_data.LAST_RED_VAL*RESO_VAL, light_data.LAST_GREEN_VAL*RESO_VAL, light_data.LAST_BLUE_VAL*RESO_VAL, light_data.LAST_WHITE_VAL*RESO_VAL, light_data.LAST_WARM_VAL*RESO_VAL);
            }
            else
            {
                send_light_data(light_data.FIN_RED_VAL, light_data.FIN_GREEN_VAL, light_data.FIN_BLUE_VAL, light_data.FIN_WHITE_VAL, light_data.FIN_WARM_VAL);
                hw_timer_disarm();
            }
            light_change=0;
            xQueueReset(Light_Queue);
            HAL_MutexUnlock(mutex_handle);
        }
    }
}

void device_init(void)
{
    Light_Queue=xQueueCreate(1,sizeof(uint8_t));
    my_pwm_init();
    hw_timer_init(light_change_timer, NULL);
    // os_timer_disarm(&os_timer);
    // os_timer_setfn(&os_timer, (os_timer_func_t *)(light_change_timer), NULL);
    os_timer_disarm(&save_data_timer);
    os_timer_setfn(&save_data_timer, (os_timer_func_t *)(save_data_timer_cb), NULL);
    os_timer_disarm(&reset_cnt_timer);
    os_timer_setfn(&reset_cnt_timer, (os_timer_func_t *)(reset_cnt_timer_cb), NULL);
    os_timer_arm(&reset_cnt_timer, 3000, 0);
    os_timer_disarm(&twinkle_timer);
    os_timer_setfn(&twinkle_timer, (os_timer_func_t *)(twinkle_timer_cb), NULL);    

    mutex_handle=HAL_MutexCreate();
    set_reset_cnt(get_reset_cnt()+1); 
    switch(get_reset_cnt())
    {
        case 1:
            light_init();
            break;
        case 2:
            send_light_data(255,0,0,0,0);
            break;
        case 3:
            send_light_data(0,255,0,0,0);
            break;
        case 4:
            send_light_data(0,0,255,0,0);       
            break;   
        default:
            router_wifi_clean_info();
            default_value();
            set_reset_cnt(0); 
            break;
    }
}

void save_data_timer_cb(void)
{
    set_flash();
}

void reset_cnt_timer_cb(void)
{
    set_reset_cnt(0);
    light_init();
}

void twinkle_timer_cb(void)
{
    static int twinkle_flag;
    if(twinkle_flag)
    {
        send_light_data(0,0,0,127,0);
        twinkle_flag=0;
    }
    else
    {
        send_light_data(0,0,0,0,0);
        twinkle_flag=1;
    }
    
}

unsigned int get_max_value(unsigned int a, unsigned int b, unsigned int c, unsigned int d, unsigned int e)
{
    unsigned int x,y,z;
	x = a > b ? a : b;
	y = c > d ? c : d;
	z = x > y ? x : y;
	return z > e ? z : e; 
}

int ABS(int value)
{
	if(value < 0){
		return 0-value;
	}else{
		return value;
	}
}

void send_light_data(uint8_t COLOR_R,uint8_t COLOR_G,uint8_t COLOR_B,uint8_t COLOR_C,uint8_t COLOR_W)
{
    pwm_val = PWM_MAX*COLOR_R/255;
    pwm_set_duty(CHANNLE_PWM_R, pwm_val);
    pwm_val = PWM_MAX*COLOR_G/255;
    pwm_set_duty(CHANNLE_PWM_G, pwm_val);
    pwm_val = PWM_MAX*COLOR_B/255;
    pwm_set_duty(CHANNLE_PWM_B, pwm_val);
    pwm_val = PWM_MAX*COLOR_C/255;
    pwm_set_duty(CHANNLE_PWM_C, pwm_val);
    pwm_val = PWM_MAX*COLOR_W/255;
    pwm_set_duty(CHANNLE_PWM_W, pwm_val);
    pwm_start();
}
void my_pwm_init(void)
{
    pwm_init(PWM_PERIOD, setDuties, CHANNLE_PWM_TOTAL, pinNum);
	pwm_set_phases(phase);
}

void get_light_data(void)
{
    if(dp_data.WORK_MODE==WHITE_MODE)
    {
		light_data.FIN_WHITE_VAL = dp_data.BRIGHT*dp_data.COL_TEMPERATURE/255;
		light_data.FIN_WARM_VAL = dp_data.BRIGHT - light_data.FIN_WHITE_VAL;
        light_data.FIN_RED_VAL = 0;
        light_data.FIN_GREEN_VAL =0;
        light_data.FIN_BLUE_VAL = 0;
        light_data.RED_VAL = light_data.FIN_RED_VAL/RESO_VAL;
        light_data.GREEN_VAL = light_data.FIN_GREEN_VAL/RESO_VAL;
        light_data.BLUE_VAL = light_data.FIN_BLUE_VAL/RESO_VAL;
        light_data.WHITE_VAL = light_data.FIN_WHITE_VAL/RESO_VAL;
        light_data.WARM_VAL = light_data.FIN_WARM_VAL/RESO_VAL;
        Log_d("C=%d,W=%d",light_data.FIN_WHITE_VAL,light_data.FIN_WARM_VAL);
    }
    else if(dp_data.WORK_MODE==COLOUR_MODE)
    {
        light_data.FIN_RED_VAL=dp_data.RED;
        light_data.FIN_GREEN_VAL=dp_data.GREEN;
        light_data.FIN_BLUE_VAL=dp_data.BLUE;
        light_data.FIN_WHITE_VAL=0;
        light_data.FIN_WARM_VAL=0;
        light_data.RED_VAL = light_data.FIN_RED_VAL/RESO_VAL;
        light_data.GREEN_VAL = light_data.FIN_GREEN_VAL/RESO_VAL;
        light_data.BLUE_VAL = light_data.FIN_BLUE_VAL/RESO_VAL;
        light_data.WHITE_VAL = light_data.FIN_WHITE_VAL/RESO_VAL;
        light_data.WARM_VAL = light_data.FIN_WARM_VAL/RESO_VAL;
    }
}

void default_value(void)
{
    dp_data.SWITCH=1;
    dp_data.BRIGHT=255;
    dp_data.COL_TEMPERATURE=255;
    dp_data.WORK_MODE=WHITE_MODE;
    dp_data.RED=255;
    dp_data.GREEN=0;
    dp_data.BLUE=0;
    set_flash();
    get_light_data();
}
void set_flash(void)
{
    nvs_handle out_handle;
    if (nvs_open("flash_info", NVS_READWRITE, &out_handle) != ESP_OK)
    {
        return;
    }
    nvs_set_u8(out_handle, "BRIGHT", dp_data.BRIGHT);
    nvs_set_u8(out_handle, "COL_TEMPERATURE", dp_data.COL_TEMPERATURE);
    nvs_set_u8(out_handle, "WORK_MODE", dp_data.WORK_MODE);
    nvs_set_u8(out_handle, "RED", dp_data.RED);
    nvs_set_u8(out_handle, "GREEN", dp_data.GREEN);
    nvs_set_u8(out_handle, "BLUE", dp_data.BLUE);
    nvs_close(out_handle);
}

void get_flash(void)
{
    nvs_handle out_handle;
    nvs_open("flash_info", NVS_READONLY, &out_handle);
    if(nvs_get_u8(out_handle,"BRIGHT",&dp_data.BRIGHT)!=ESP_OK){
        dp_data.BRIGHT=255;
    }
    else{
        Log_d("\n dp_data.BRIGHT=%d\n",dp_data.BRIGHT);
    }
    if(nvs_get_u8(out_handle,"COL_TEMPERATURE",&dp_data.COL_TEMPERATURE)!=ESP_OK){
        dp_data.COL_TEMPERATURE=255;
    }
    else{
        Log_d("\n dp_data.COL_TEMPERATURE=%d\n",dp_data.COL_TEMPERATURE);
    }
    if(nvs_get_u8(out_handle,"WORK_MODE",&dp_data.WORK_MODE)!=ESP_OK){
        dp_data.WORK_MODE=WHITE_MODE;
    }
    else{
        Log_d("\ndp_data.WHITE_MODE=%d\n",dp_data.WORK_MODE);
    }
    if(nvs_get_u8(out_handle,"RED",&dp_data.RED)!=ESP_OK){
        dp_data.RED=255;
    }
    else{
        Log_d("\n dp_data.RED=%d\n",dp_data.RED);
    }
    if(nvs_get_u8(out_handle,"GREEN",&dp_data.GREEN)!=ESP_OK){
        dp_data.GREEN=0;
    }
    else{
        Log_d("\n dp_data.GREEN=%d\n",dp_data.GREEN);
    }       
    if(nvs_get_u8(out_handle,"BLUE",&dp_data.BLUE)!=ESP_OK){
        dp_data.BLUE=0;
    }
    else{
        Log_d("\n dp_data.BLUE=%d\n",dp_data.BLUE);
    }        
    nvs_close(out_handle);
}

void light_init(void)
{
    get_flash();
    dp_data.SWITCH=1;
	if(dp_data.SWITCH == 1)
    {
		get_light_data();
		switch(dp_data.WORK_MODE)
		{
			case WHITE_MODE:
			case COLOUR_MODE:
				light_data.LAST_RED_VAL = light_data.FIN_RED_VAL/RESO_VAL;
				light_data.LAST_GREEN_VAL = light_data.FIN_GREEN_VAL/RESO_VAL;
				light_data.LAST_BLUE_VAL = light_data.FIN_BLUE_VAL/RESO_VAL;
				light_data.LAST_WHITE_VAL = light_data.FIN_WHITE_VAL/RESO_VAL;
				light_data.LAST_WARM_VAL = light_data.FIN_WARM_VAL/RESO_VAL;
				send_light_data(light_data.FIN_RED_VAL,light_data.FIN_GREEN_VAL,light_data.FIN_BLUE_VAL,light_data.FIN_WHITE_VAL,light_data.FIN_WARM_VAL);
				break;
			default:
				break;		
		}
	}
}

void router_wifi_save_info(uint8_t *ssid, uint8_t *password)
{
    nvs_handle out_handle;
    char data[65];
    if (nvs_open("wifi_info", NVS_READWRITE, &out_handle) != ESP_OK)
    {
        return;
    }

    memset(data, 0x0, sizeof(data));
    strncpy(data, (char *)ssid, strlen((char *)ssid));
    if (nvs_set_str(out_handle, "ssid", data) != ESP_OK)
    {
        Log_d("--set ssid fail");
    }

    memset(data, 0x0, sizeof(data));
    strncpy(data, (char *)password, strlen((char *)password));
    if (nvs_set_str(out_handle, "password", data) != ESP_OK)
    {
        Log_d("--set password fail");
    }
    nvs_close(out_handle);
}
void router_wifi_clean_info(void)
{
    nvs_handle out_handle;
    if (nvs_open("wifi_info", NVS_READWRITE, &out_handle) == ESP_OK)
    {
        nvs_erase_all(out_handle);
        nvs_close(out_handle);
    }
}

bool router_wifi_read()
{
    nvs_handle out_handle;
    size_t size = 0;
    nvs_open("wifi_info", NVS_READONLY, &out_handle);
    memset(&wifi_config, 0x0, sizeof(wifi_config));
    size = sizeof(wifi_config.sta.ssid);
    if(nvs_get_str(out_handle, "ssid", (char *)wifi_config.sta.ssid, &size) == ESP_OK)
    {
        if (size > 0)
        {
            size = sizeof(wifi_config.sta.password);
            if (nvs_get_str(out_handle, "password", (char *)wifi_config.sta.password, &size) == ESP_OK)
            {
                Log_d("-- get ssid: %s", wifi_config.sta.ssid);
                Log_d("-- get password: %s", wifi_config.sta.password);
                return 1;
            }
        }
    }
    nvs_close(out_handle);
    return 0;
}
void set_reset_cnt(uint8_t cnt)
{
    nvs_handle out_handle;
    if (nvs_open("reset_cnt", NVS_READWRITE, &out_handle) != ESP_OK)
    {
        return;
    }
    nvs_set_u8(out_handle, "reset_cnt", cnt);
    nvs_close(out_handle);
}

uint8_t get_reset_cnt()
{
    uint8_t reset_cnt;
    nvs_handle out_handle;
    nvs_open("reset_cnt", NVS_READONLY, &out_handle);
    if(nvs_get_u8(out_handle,"reset_cnt",&reset_cnt)==ESP_OK)
    {
        Log_d("\n reset_cnt=%d\n",reset_cnt);
    }
    nvs_close(out_handle);
    return reset_cnt;
}

void set_test_cnt(uint32_t cnt)
{
    nvs_handle out_handle;
    if (nvs_open("test_cnt", NVS_READWRITE, &out_handle) != ESP_OK)
    {
        return;
    }
    nvs_set_u32(out_handle, "test_cnt", cnt);
    nvs_close(out_handle);
}

uint32_t get_test_cnt()
{
    uint32_t test_cnt;
    nvs_handle out_handle;
    nvs_open("test_cnt", NVS_READONLY, &out_handle);
    if(nvs_get_u32(out_handle,"test_cnt",&test_cnt)==ESP_OK)
    {
        Log_d("test_cnt=%d",test_cnt);
    }
    nvs_close(out_handle);
    return test_cnt;
}

void factory_test(void)
{
    char *ssid_test="cong"; //产测路由，自定义
    static wifi_scan_config_t scanConf  = {
    .ssid = NULL,
    .bssid = NULL,
    .channel = 0,
    .show_hidden = 1
    };//定义scanConf结构体，供函数esp_wifi_scan_start调用
    uint16_t apCount = 0;
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();//设置默认的wifi栈参数
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));    //初始化WiFi Alloc资源为WiFi驱动，如WiFi控制结构，RX / TX缓冲区，WiFi NVS结构等，此WiFi也启动WiFi任务。
    ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));// Set the WiFi API configuration storage type
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));//Set the WiFi operating mode
    ESP_ERROR_CHECK(esp_wifi_start());

    ESP_ERROR_CHECK(esp_wifi_scan_start(&scanConf, 1));

    esp_wifi_scan_get_ap_num(&apCount);//Get number of APs found in last scan
    Log_d("Number of access points found: %d\n", apCount);
    if (apCount == 0) {
        Log_d("Nothing AP found");
        return;
    }//如果apCount没有受到数据，则说明没有路由器
    wifi_ap_record_t *list = (wifi_ap_record_t *)malloc(sizeof(wifi_ap_record_t) * apCount);//定义一个wifi_ap_record_t的结构体的链表空间
    ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&apCount, list));//获取上次扫描中找到的AP列表。
    for (int i=0; i<apCount; i++) 
    {
        Log_d("%s|%d\n",list[i].ssid, list[i].rssi);//将链表的数据信息打印出来
        if(strcmp(&list[i].ssid,ssid_test)==0)
        {
            Log_e("test ssid is find\n");
            if(list[i].rssi<-60)
            {
                Log_d("rssi is too weak");
            }
            else
            {
                os_timer_disarm(&test_timer);
                os_timer_setfn(&test_timer, (os_timer_func_t *)(test_timer_cb), NULL);   
                os_timer_arm(&test_timer,1000,1);
                while(1)
                {
                    HAL_SleepMs(2000);
                }
            }
            break;
        }
    }
    free(list);//释放链表
}

void test_timer_cb(void)
{
    int test_cnt;
    test_cnt=get_test_cnt()+1;
    if(test_cnt<120)
    {
        switch(test_cnt%5)
        {
            case 1:
                send_light_data(255,0,0,0,0);
                Log_d("test_color_r");
                break;
            case 2:
                send_light_data(0,255,0,0,0);
                Log_d("test_color_g");
                break;
            case 3:
                send_light_data(0,0,255,0,0);
                Log_d("test_color_b");
                break;
            case 4:
                send_light_data(0,0,0,255,0);
                Log_d("test_color_c");
                break;
            case 0:
                send_light_data(0,0,0,0,255);
                Log_d("test_color_w");
                break;     
            default:   
                break;                                       
        }
    }
    if(test_cnt==120)
    {
        Log_d("color test end, aging test start");
         send_light_data(0,0,0,255,0);
    }
    else if(120 < test_cnt && test_cnt <= (aging_test_c*60 + 120))
    {
        send_light_data(0,0,0,255,0);
        Log_d("aging test color_c");
    }
    else if((aging_test_c*60 + 120) < test_cnt && test_cnt <= (aging_test_c*60 + aging_test_w*60 + 120))
    {
        send_light_data(0,0,0,0,255);
        Log_d("aging test color_w");
    }
    else if((aging_test_c*60 + aging_test_w*60 + 120) < test_cnt && test_cnt <= (aging_test_c*60 + aging_test_w*60 + aging_test_rgb*60 + 120))
    {
        send_light_data(255,255,255,0,0);
        Log_d("aging test color_rgb");
    }
    else if( test_cnt > ( aging_test_c*60 + aging_test_w*60 + aging_test_rgb*60 + 120 ))
    {
        send_light_data(0,255,0,0,0);
        Log_d("aging test end");
        test_cnt=0;
        os_timer_disarm(&test_timer);
    }
    set_test_cnt(test_cnt);
}

void uart_event_task(void* parm)
{
    uart_event_t event;
    uint8_t *dtmp = (uint8_t *) malloc(RD_BUF_SIZE);
    char *ret;
    char uart_buf[150];
    uint8_t pid_len=0;
    uint8_t dn_len=0;

    while(1)
    {
        // Waiting for UART event.
        if (xQueueReceive(uart0_queue, (void *)&event, portMAX_DELAY)) 
        {
            // bzero(dtmp, RD_BUF_SIZE);
            memset(dtmp,0,RD_BUF_SIZE);
            memset(uart_buf,0,150);
            switch (event.type) 
            {
                // Event of UART receving data
                // We'd better handler data event fast, there would be much more data events than
                // other types of events. If we take too much time on data event, the queue might be full.
                case UART_DATA:
                    // Log_i("[UART DATA]: %d", event.size);                                   
                    uart_read_bytes(EX_UART_NUM, dtmp, event.size, portMAX_DELAY);   
                    if((ret = strstr((const char *)dtmp, "product_id="))!=NULL)
                    {
                        Log_d("%s", ret);
                        memset(sg_product_id,0,sizeof(sg_product_id));
                        memcpy(sg_product_id,dtmp+11,event.size-11);
                        Log_d("id=%s",sg_product_id);   
                        set_product_Info();
                    }
                    else if((ret = strstr((const char *)dtmp, "device_name="))!=NULL)
                    {
                        Log_d("%s", ret);
                        memset(sg_device_name,0,sizeof(sg_device_name));
                        memcpy(sg_device_name,dtmp+12,event.size-12);
                        Log_d("name=%s",sg_device_name);   
                        set_product_Info();
                    }
                    else if((ret = strstr((const char *)dtmp, "product_secret="))!=NULL)
                    {
                        Log_d("%s", ret);
                        memset(sg_product_secret,0,sizeof(sg_product_secret));
                        memcpy(sg_product_secret,dtmp+15,event.size-15);
                        Log_d("ps=%s",sg_product_secret);   
                        set_product_Info();
                    }
                    else if((ret = strstr((const char *)dtmp, "device_secret="))!=NULL)
                    {
                        Log_d("%s", ret);
                        memset(sg_device_secret,0,sizeof(sg_device_secret));
                        memcpy(sg_device_secret,dtmp+14,event.size-14);
                        Log_d("ds=%s",sg_device_secret);   
                        set_product_Info();
                    } 
                    else if((ret = strstr((const char *)dtmp, "region="))!=NULL)
                    {
                        Log_d("%s", ret);
                        memset(sg_region,0,sizeof(sg_region));
                        memcpy(sg_region,dtmp+7,event.size-7);
                        Log_d("region=%s",sg_region);   
                        set_product_Info();
                    }    
                   else if((ret = strstr((const char *)dtmp, "product_info="))!=NULL)   //一次输入三元组信息product_info=product_id device_name device_secret 
                   {
                       memcpy(uart_buf,dtmp+13,event.size);

                        if((ret=strstr((const char *)dtmp," "))!=NULL)
                        {
                            // Log_d("%s",ret);
                            pid_len=strlen(uart_buf)-strlen(ret);
                            // Log_d("pid_len=%d",pid_len);
                            memset(sg_product_id,0,sizeof(sg_product_id));
                            memcpy(sg_product_id,uart_buf,pid_len);
                            Log_d("sg_product_id=%s",sg_product_id);
                            memset(uart_buf,0,150);
                            memcpy(uart_buf,ret+1,strlen(ret));
                        }
                        if((ret=strstr((const char *)uart_buf," "))!=NULL)
                        {
                            // Log_d("%s",ret);
                            dn_len=strlen(uart_buf)-strlen(ret);
                            // Log_d("dn_len=%d",dn_len);
                            memset(sg_device_name,0,sizeof(sg_device_name));
                            memcpy(sg_device_name,uart_buf,dn_len);
                            Log_d("sg_device_name=%s",sg_device_name);
                            memset(sg_device_secret,0,sizeof(sg_device_secret));
                            memcpy(sg_device_secret,ret+1,strlen(ret));
                            Log_d("sg_device_secret=%s",sg_device_secret);
                            set_product_Info();    
                            router_wifi_clean_info();
                            default_value();
                            HAL_SleepMs(1500);                  
                            esp_restart();
                        }
                   }          
                    else if(strcmp((const char *)dtmp,"restart")==0) esp_restart();   //系统复位

                    uart_write_bytes(EX_UART_NUM, (const char *) dtmp, event.size);
                    break;
                // Event of HW FIFO overflow detected
                case UART_FIFO_OVF:
                    Log_i("hw fifo overflow");        
                    // If fifo overflow happened, you should consider adding flow control for your application.
                    // The ISR has already reset the rx FIFO,
                    // As an example, we directly flush the rx buffer here in order to read more data.
                    uart_flush_input(EX_UART_NUM);
                    xQueueReset(uart0_queue);
                    break;

                // Event of UART ring buffer full
                case UART_BUFFER_FULL:
                    Log_i("ring buffer full");
                    // If buffer full happened, you should consider encreasing your buffer size
                    // As an example, we directly flush the rx buffer here in order to read more data.
                    uart_flush_input(EX_UART_NUM);
                    xQueueReset(uart0_queue);
                    break;

                case UART_PARITY_ERR:
                    Log_i("uart parity error");
                    break;

                // Event of UART frame error
                case UART_FRAME_ERR:
                    Log_i("uart frame error");
                    break;

                // Others
                default:
                    Log_i("uart event type: %d", event.type);
                    break;
            }
        }
    }

    free(dtmp);
    dtmp = NULL;
    vTaskDelete(NULL);
}

void set_product_Info()
{
    nvs_handle out_handle;
    if (nvs_open("product_Info", NVS_READWRITE, &out_handle) != ESP_OK)
    {
        return;
    }
    nvs_set_str(out_handle, "product_id", sg_product_id);
    nvs_set_str(out_handle, "device_name", sg_device_name);
    nvs_set_str(out_handle, "product_secret", sg_product_secret);
    nvs_set_str(out_handle, "device_secret", sg_device_secret);
    nvs_set_str(out_handle, "region", sg_region);
    nvs_commit(out_handle);
    nvs_close(out_handle);
}

void get_product_Info()
{
    size_t size;
    nvs_handle handle;
    nvs_open("product_Info", NVS_READONLY, &handle);
    size=sizeof(sg_product_id);
    if(nvs_get_str(handle,"product_id",sg_product_id,&size)==ESP_OK)
    {
        Log_d("product_id=%s",sg_product_id);
    }
    size=sizeof(sg_device_name);
    if(nvs_get_str(handle,"device_name",sg_device_name,&size)==ESP_OK)
    {
        Log_d("device_name=%s",sg_device_name);
    }
    size=sizeof(sg_product_secret);
    if(nvs_get_str(handle,"product_secret",sg_product_secret,&size)==ESP_OK)
    {
        Log_d("product_secret=%s",sg_product_secret);
    }
    size=sizeof(sg_device_secret);
    if(nvs_get_str(handle,"device_secret",sg_device_secret,&size)==ESP_OK)
    {
        Log_d("device_secret=%s",sg_device_secret);
    }
    size=sizeof(sg_region);
    if(nvs_get_str(handle,"region",sg_region,&size)==ESP_OK)
    {
        Log_d("region=%s",sg_region);
    }
    nvs_close(handle);
}

void app_main()
{
    ESP_ERROR_CHECK(nvs_flash_init());
    IOT_Log_Set_Level(eLOG_DEBUG);
    uart_param_config(EX_UART_NUM, &uart_config);
    // Install UART driver, and get the queue.
    uart_driver_install(EX_UART_NUM, BUF_SIZE * 2, BUF_SIZE * 2, 100, &uart0_queue); 
    get_product_Info();
    // init log level
	device_init();

    xTaskCreate(uart_event_task, "uart_event_task", 2048, NULL, 10, NULL);

 	xTaskCreate(light_change_task, "light_change_task", 1024+512, NULL, 11, NULL);

    xTaskCreate(qcloud_demo_task, "qcloud_demo_task", 8196, NULL, 4, NULL);
}